package dominio;

import java.util.ArrayList;

import org.uqbar.commons.utils.Observable;

public class Tablero {

	protected int nroFilas;
	protected int nroColumnas;
	protected Caramelo[][] matrizTablero;
	final Dificultad dificultad;
	
	public Tablero(Dificultad dificultad,int nroFilas, int nroColumnas){
		this.nroFilas = nroFilas;
		this.nroColumnas = nroColumnas;
		this.matrizTablero = new Caramelo[nroFilas][nroColumnas];
		this.dificultad = dificultad;
	}
	
	//*************************************** Accesors **************************************************
	@Observable
	public int getNroFilas() {
		return nroFilas;
	}

	public void setNroFilas(int nroFilas) throws UserException {
		if (Validacion.esNegativo(nroFilas)){
			throw new UserException("Debe Ser positivo!");		
		}else{
			this.nroFilas = nroFilas;
		}
	}

	public int getNroColumnas() {
		return nroColumnas;
	}

	public void setNroColumnas(int nroColumnas) throws UserException {
		if (Validacion.esNegativo(nroColumnas)){
			throw new UserException("Debe Ser positivo!");
		}else{
			this.nroColumnas = nroColumnas;
		}
	}

	public Caramelo[][] getMatrizTablero() {
		return matrizTablero;
	}

	public void setMatrizTablero(Caramelo[][] matrizTablero) {
		this.matrizTablero = matrizTablero;
	}

	//**********************************************************************************************************

	/*
	 * Inserta un caramelo en la posicion pasada como parametro.
	 */
	public void insertInto(int fila,int columna, Caramelo c){
		this.matrizTablero [fila][columna] = c;
	}
	
	/*
	 * Muestra en consola el tablero.
	 */
	public void mostrarTablero(){
		for (int i = 0; i < this.nroFilas; i++) {
            for (int j = 0; j < this.nroColumnas; j++) {
            	if(this.matrizTablero[i][j] == null){
            		System.out.print("null ");
            	}
            	else{
            		System.out.print(this.matrizTablero[i][j].getColor() + " ");
            	}
            }
            System.out.print("\n");
        }
	}

	
	//**************************************************** Aplicar gravedad a caramelos *************************************************************
	
	/*
	 * Baja todos los caramelos en los lugares donde hayan explotado caramelos.
	 */
	public void aplicarGravedad(){
		for(int i=0; i<this.nroColumnas; i++){
			this.aplicarGravedadColumna(i);
		}
	}
	
	/*
	 * Hace el aplicar gravedad para la columna indicada
	 */
	public void aplicarGravedadColumna(int nroColumna){
		ArrayList<Posicion> posiciones = new ArrayList<Posicion>();
		boolean primerPosLibre = false;		//Sirve para verificar a partir de donde empiezan los espacios vacios				
		for(int i= this.nroFilas-1; i>= 0; i--){  //Recorro todas las filas de la columna
			if((this.matrizTablero [i][nroColumna]) != null){      
				if(primerPosLibre) {posiciones.add(new Posicion(nroColumna,i));}
			}else{
				primerPosLibre = true;
				posiciones.add(new Posicion(nroColumna,i));
			}
		}
		this.cambiarCaramelos(posiciones);
	}
	
	/*
	 * Cuenta los espacios vacios (null) que hay en la columna.
	 */
	public int contarVaciosEnColumna(ArrayList<Posicion> pos){
		int longArray = pos.size();
		int cont = 0;
		for(int i=0; i<longArray; i++){
			Posicion posAux = pos.get(i);
			if(this.matrizTablero[posAux.getY()][posAux.getX()] == null){cont++;}
		}
		return cont;
	}
	/*
	 * Bajo los caramelos que quedaron mas arriba de las explociones realizadas.
	 */
	public void cambiarCaramelos(ArrayList<Posicion> pos){
		ArrayList<Posicion> posiciones = new ArrayList<Posicion>();
		posiciones = pos;
		int longArray = posiciones.size() - 1;
		int cantPasadas = this.contarVaciosEnColumna(posiciones);
		for(int i=0; i<cantPasadas; i++)
			for(int j=0; j<longArray; j++){
				Posicion pos1 = posiciones.get(j);
				Posicion pos2 = posiciones.get(j+1);
				this.matrizTablero [pos1.getY()][pos1.getX()] = this.matrizTablero [pos2.getY()][pos2.getX()];
				this.matrizTablero [pos2.getY()][pos2.getX()] = null;
			}
	}
	
	//***********************************************************************************************************************************************
	//***********************************************************************************************************************************************
	
	//************************************************************* Swap ****************************************************************************
	
	public void swap(Posicion pos1, Posicion pos2){
		Caramelo carameloASwapear = this.matrizTablero[pos1.getY()][pos1.getX()];
		this.matrizTablero[pos1.getY()][pos1.getX()] = this.matrizTablero[pos2.getY()][pos2.getX()];
		this.matrizTablero[pos2.getY()][pos2.getX()] = carameloASwapear;
	}
	
	//***********************************************************************************************************************************************
	//***********************************************************************************************************************************************
	
	
	/*
	 * Rellena los espacios explotados.
	 */
	public void rellenarEspaciosLibres(){
		for (int i = 0; i < this.nroFilas; i++) 
            for (int j = 0; j < this.nroColumnas; j++) 
            	if(this.matrizTablero[i][j] == null){
            		this.matrizTablero[i][j] = this.dificultad.getRandomCaramelo();
            	}
	}
	
	/*
	 * Inicia el tablero haciendo random sobre la lista de caramelos pasada como parametro.
	 */
	public void iniciarTablero(){
		for (int i = 0; i < this.nroFilas; i++) 
            for (int j = 0; j < this.nroColumnas; j++) 
            	this.matrizTablero [i][j] = this.dificultad.getRandomCaramelo();
	}
	
	/*
	 * Realiza la propagacion de la explocion, si se puede, aplica la gravedad y rellena aleatoriamente los espacion explotados.
	 */
	public void realizarExplocion(int nroFila, int nroColumna, Movimiento mov){
		if(mov.chequearMovimiento(nroFila, nroColumna,this)){
			Resultado res = mov.explotar(nroFila,nroColumna,this);
			System.out.println(res.colorCaramelo);
			System.out.println(res.cantExplosiones);
			this.aplicarGravedad();
			this.rellenarEspaciosLibres();
		}
		else{
			System.out.println("No se puede realizar movimiento");  //Hay que lanzar una excepcion.
		}
	}
}
